package com.itheima.elasticsearch;

import com.alibaba.fastjson.JSON;
import com.itheima.elasticsearch.domain.Goods;
import com.itheima.elasticsearch.mapper.GoodsMapper;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.IndicesClient;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;
import org.elasticsearch.cluster.metadata.MappingMetaData;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@SpringBootTest
class ElasticsearchApplicationTests2 {
    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Autowired
    private GoodsMapper goodsMapper;

    //批量操作
    @Test
    void bulk() throws Exception {

        BulkRequest bulkRequest = new BulkRequest();

        DeleteRequest deleteRequest = new DeleteRequest("person").id("1");
        bulkRequest.add(deleteRequest);

        Map <String, Object> map = new HashMap <>();
        map.put("name", "赵六");
        map.put("age", 25);
        map.put("address", "重庆");
        IndexRequest indexRequest = new IndexRequest("person").id("4").source(map);
        bulkRequest.add(indexRequest);

        UpdateRequest updateRequest = new UpdateRequest("person", "2").doc(map);
        bulkRequest.add(updateRequest);

        restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
    }

    //批量导入
    @Test
    void bulkImport() throws Exception {
        List <Goods> goodsList = goodsMapper.findAll();

//        System.out.println(goodsList.get(1));

        BulkRequest bulkRequest = new BulkRequest();

        for (Goods goods : goodsList) {
            String specStr = goods.getSpecStr();
            Map map = JSON.parseObject(specStr, Map.class);
            goods.setSpec(map);

            String goodsToJSON = JSON.toJSONString(goods);

            IndexRequest indexRequest = new IndexRequest("goods").id(goods.getId() + "").source(goodsToJSON, XContentType.JSON);

            bulkRequest.add(indexRequest);
        }

        restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
    }

    /**
     * 查询所有 并分页查询（默认分10条）
     *
     * @throws Exception
     */
    @Test
    void matchAll() throws Exception {
        SearchRequest searchRequest = new SearchRequest("goods");

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();

        sourceBuilder.query(queryBuilder);

//        sourceBuilder.from(0);
//        sourceBuilder.size(100);

        searchRequest.source(sourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        SearchHits hits = search.getHits();

        TotalHits totalHits = hits.getTotalHits();
        long total = totalHits.value;

        SearchHit[] searchHits = hits.getHits();

        List <Goods> goodsList = new ArrayList <>();
        for (SearchHit searchHit : searchHits) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            goodsList.add(goods);
        }

        System.out.println("总数：" + total);
        for (Goods goods : goodsList) {
            System.out.println(goods);
        }
    }

    /**
     * 条件查询 termQuery
     *
     * @throws Exception
     */
    @Test
    void termQuery() throws Exception {

        SearchRequest searchRequest = new SearchRequest();

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        QueryBuilder queryBuilder = QueryBuilders.termQuery("brandName", "三星");
        sourceBuilder.query(queryBuilder);

        searchRequest.source(sourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        SearchHits hits = search.getHits();
        SearchHit[] searchHits = hits.getHits();

        System.out.println(hits.getTotalHits().value);
        for (SearchHit searchHit : searchHits) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            System.out.println(goods);
        }

    }

    /**
     * 条件查询 matchQuery
     *
     * @throws Exception
     */
    @Test
    void matchQuery() throws Exception {
        SearchRequest searchRequest = new SearchRequest();

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

//        QueryBuilder queryBuilder = QueryBuilders.matchQuery("title","华为");
        MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery("title", "华为");

        queryBuilder.operator(Operator.AND);//求并集    Operator.or 求合集
        sourceBuilder.query(queryBuilder);
        searchRequest.source(sourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        SearchHits hits = search.getHits();
        SearchHit[] searchHits = hits.getHits();

        System.out.println(hits.getTotalHits().value);
        for (SearchHit searchHit : searchHits) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            System.out.println(goods);
        }

    }

    /**
     * 模糊查询 不能在查询条件前加 通配符  否则会让索引失效
     *
     * @throws Exception
     */
    @Test
    void wildcardQuery() throws Exception {
        SearchRequest searchRequest = new SearchRequest();

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        QueryBuilder queryBuilder = QueryBuilders.wildcardQuery("title", "阿尔卡特*");

        sourceBuilder.query(queryBuilder);
        searchRequest.source(sourceBuilder);

        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        SearchHits hits = search.getHits();
        SearchHit[] searchHits = hits.getHits();

        System.out.println(hits.getTotalHits().value);
        for (SearchHit searchHit : searchHits) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            System.out.println(goods);
        }
    }

    /**
     * 模糊查询  正则  regexpQuery
     *
     * @throws Exception
     */
    @Test
    void regexpQuery() throws Exception {
        SearchRequest searchRequest = new SearchRequest();

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        QueryBuilder queryBuilder = QueryBuilders.regexpQuery("title", "\\w+(.)*");
        sourceBuilder.query(queryBuilder);

        searchRequest.source(sourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        SearchHits hits = search.getHits();
        SearchHit[] searchHits = hits.getHits();

        System.out.println(hits.getTotalHits().value);
        for (SearchHit searchHit : searchHits) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            System.out.println(goods);
        }
    }

    /**
     * 模糊查询  开头字符匹配查询
     *
     * @throws Exception
     */
    @Test
    void prefixQuery() throws Exception {
        SearchRequest searchRequest = new SearchRequest();

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        QueryBuilder queryBuilder = QueryBuilders.prefixQuery("title", "三");
        sourceBuilder.query(queryBuilder);

        searchRequest.source(sourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        SearchHits hits = search.getHits();
        SearchHit[] searchHits = hits.getHits();

        System.out.println(hits.getTotalHits().value);
        for (SearchHit searchHit : searchHits) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            System.out.println(goods);
        }
    }

    /**
     * 范围查询
     *
     * @throws Exception
     */
    @Test
    void rangeQuery() throws Exception {
        SearchRequest searchRequest = new SearchRequest();

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        RangeQueryBuilder queryBuilder = QueryBuilders.rangeQuery("price");

        queryBuilder.gte(2000);//大于  gt 大于等于
        queryBuilder.lte(4000);//小于  lt 小于等于

        sourceBuilder.sort("price", SortOrder.DESC); //按price排序

        sourceBuilder.query(queryBuilder);

        searchRequest.source(sourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        SearchHits hits = search.getHits();
        SearchHit[] searchHits = hits.getHits();

        System.out.println(hits.getTotalHits().value);
        for (SearchHit searchHit : searchHits) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            System.out.println(goods);
        }
    }

    /**
     * queryStringQuery 同时对多个字段（倒排索引的key）进行等值匹配
     *
     * @throws Exception
     */
    @Test
    void queryStringQuery() throws Exception {
        SearchRequest searchRequest = new SearchRequest();

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        QueryBuilder queryBuilder = QueryBuilders.queryStringQuery("华为手机").field("title").field("brandName").defaultOperator(Operator.AND);
        sourceBuilder.query(queryBuilder);

        searchRequest.source(sourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        SearchHits hits = search.getHits();
        SearchHit[] searchHits = hits.getHits();

        System.out.println(hits.getTotalHits().value);
        for (SearchHit searchHit : searchHits) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            System.out.println(goods);
        }
    }

    /**
     * bool查询
     * must:必须满足需求，同时参与计算分值
     * must_not:不能满足
     * should:可以满足
     * filter:必须满足，但不会参与计算分值
     *
     * @throws Exception
     */
    @Test
    void boolQuery() throws Exception {
        SearchRequest searchRequest = new SearchRequest();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        QueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("categoryName", "手机");
        queryBuilder.must(matchQueryBuilder);

        QueryBuilder termQueryBuilder = QueryBuilders.termQuery("brandName", "小米");
        queryBuilder.filter(termQueryBuilder);

        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("price");
        rangeQueryBuilder.gte(2000);
        rangeQueryBuilder.lte(3500);
        queryBuilder.filter(rangeQueryBuilder);

        sourceBuilder.query(queryBuilder);
        searchRequest.source(sourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        SearchHits hits = search.getHits();
        SearchHit[] searchHits = hits.getHits();

        System.out.println(hits.getTotalHits().value);
        for (SearchHit searchHit : searchHits) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            System.out.println(goods);
        }
    }

    /**
     * 聚合查询  桶查询   查询品牌分组
     *
     * @throws Exception
     */
    @Test
    void aggQuery() throws Exception {
        SearchRequest searchRequest = new SearchRequest();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        AggregationBuilder aggregation = AggregationBuilders.terms("goods_brand").field("brandName").size(100);
        //terms：定义属性别名 field：需要查询的属性 
        //AggregationBuilders.max  min  指数查询，查询最大或最小值
        sourceBuilder.aggregation(aggregation);
        searchRequest.source(sourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        Aggregations aggregations = search.getAggregations();
        Map <String, Aggregation> stringAggregationMap = aggregations.asMap();
        Terms goods_brands = (Terms) stringAggregationMap.get("goods_brand");

        List <? extends Terms.Bucket> buckets = goods_brands.getBuckets();
        for (Terms.Bucket bucket : buckets) {
            System.out.println(bucket.getKey());
        }
    }

    /**
     * 高亮查询
     *
     * @throws Exception
     */
    @Test
    void highLightQuery() throws Exception {
        SearchRequest searchResquest = new SearchRequest();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        HighlightBuilder highLightBuilder = new HighlightBuilder().field("title");
        highLightBuilder.preTags("<font color='red'>");
        highLightBuilder.postTags("</font>");

        sourceBuilder.highlighter(highLightBuilder);
        QueryBuilder queryBuilder = QueryBuilders.termQuery("title", "华为");
        sourceBuilder.query(queryBuilder);
        searchResquest.source(sourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchResquest, RequestOptions.DEFAULT);

        SearchHits hits = search.getHits();
        SearchHit[] searchHits = hits.getHits();

        System.out.println(hits.getTotalHits().value);
        for (SearchHit searchHit : searchHits) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            Map <String, HighlightField> highlightFields = searchHit.getHighlightFields();
            HighlightField title = highlightFields.get("title");
            Text[] fragments = title.fragments();
            goods.setTitle(fragments[0].toString());
            System.out.println(goods);
        }
    }

}
